package cn.mabach.filter;


import cn.mabach.utils.TokenDecode;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: ming
 * @Date: 2020/2/7 0007 下午 1:21
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {
    @Autowired
    private StringRedisTemplate redisTemplate;


    private static final String AUTHORIZE_TOKEN = "Authorization";

    private static final String LOGIN_URL="http://www.mabach.cn/api-oauth/toLogin";
    private static final String HOST="http://www.mabach.cn";

//
    private String accessUrl="/api-oauth/toLogin,/qqloginback,/api-oauth/code/image,/api-oauth/toLogin/mobile," +
            "/api-oauth/login,/api-oauth/code/image,/api-oauth/mobile/login,/api-oauth/code/mobile,/api-oauth/toQQLogin," +
            "/api-oauth/login/qq,/api-oauth/relateQQ,/api-oauth/register/qq,/api-oauth/preqq,/api-oauth/logout,/api-portal/portal/register," +
            "/api-portal/portal/signin,/api-portal/portal/prelogin";

//    private String accessUrl="/api-oauth/**";



    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {


        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();


//将第一次请求的地址以ip为key存入redis
        getLastUrl(request);


//        获取当前请求,如果是登录请求则放行
        String path = request.getURI().getPath();

        if (isAccess(path)){
            return chain.filter(exchange);
        }

//如果从请求头获取到token,且不过期，则放行
        String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);

        if (!StringUtils.isEmpty(token)){
            log.info("从请求头获取到了token: {}",token);
            //        解析令牌判断是否过期,过期则跳转到登录地址
            if (isExpri(token)) {
                return getVoidMono(LOGIN_URL, response);
            }

           return chain.filter(exchange);

        }

//从请求头获取不到就从cookie中获取
        if (StringUtils.isEmpty(token)){

            token = getCookies(request);
            log.info("从cookies中获取到token:{}",token);
        }


        //如果cookie不存在令牌,则从请求参数中获取
        if (StringUtils.isEmpty(token)){


            token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
        }

//如果token获取不到,则跳转到登录地址，带上原地址
        if (StringUtils.isEmpty(token)){


            //获取上一次请求地址


            String ip = request.getRemoteAddress().getHostString();
            log.info("请求ip:{}",ip);


                String lastUrl = redisTemplate.boundValueOps(ip).get();



            return getVoidMono(LOGIN_URL+"?from="+lastUrl, response);
        }

//        判断token是否过期，过期则跳转到登录页面
        if (isExpri(token)){
            String ip = request.getRemoteAddress().getHostString();
            String lastUrl = redisTemplate.boundValueOps(ip).get();


            return getVoidMono(LOGIN_URL+"?from="+lastUrl, response);
        }


//        如果能从cookies获取到token，则添加到头信息
        request.mutate().header(AUTHORIZE_TOKEN,"Bearer "+ token);

//        放行
        return chain.filter(exchange);

    }




//    解析令牌是否过期
    private boolean isExpri(String token) {
        String bearer = token.replace("Bearer ", "");
        String decode = null;
        try {
            decode = TokenDecode.decode(bearer);
        } catch (Exception e) {
            return true;

        }

        Map<String,Integer> map = JSON.parseObject(decode, Map.class);
        long exp = map.get("exp").longValue();

//获取当前秒单位的时间戳
        long epochSecond = Instant.now().getEpochSecond();

//        如果令牌过期则跳转到登录页
        if (epochSecond>=exp){
            log.info("token过期:{}",exp);
            return true;
        }
        return false;
    }


    private Mono<Void> getVoidMono(String url, ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.SEE_OTHER);//303
        //   跳转
        response.getHeaders().add("Location",url);
        return response.setComplete();
    }

    private Boolean isAccess(String url){
        AntPathMatcher pathMatcher = new AntPathMatcher();
        String[] split = accessUrl.split(",");
        System.out.println(split);
        for (String s : split) {

            if (pathMatcher.match(s,url)){

                return true;
            }
        }
        return false;
    }

//  获取cookies
    private String getCookies(ServerHttpRequest request) {

        HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);
        if (cookie!=null){
            return cookie.getValue();
        }

        return null;
    }



//    获取上一次请求地址
    private void getLastUrl(ServerHttpRequest request){

        String s = request.getURI().toString();
        String[] split = accessUrl.split(",");
        for (String s1 : split) {
            if (s.contains(s1)){
                return;
            }
        }


        int i = s.indexOf("/api");
            String substring = s.substring(i);
            String url = HOST+substring;
            log.info("上一次请求地址是：{}",url);

        String ip = request.getRemoteAddress().getHostString();

        redisTemplate.boundValueOps(ip).set(url,60*2, TimeUnit.SECONDS);



    }


    @Override
    public int getOrder() {
        return 0;
    }


}
